using System;
using System.IO;

namespace SharpCompress.Common.Rar.Headers
{
    internal class MarkHeader : IRarHeader
    {
        private const int MAX_SFX_SIZE = 0x80000 - 16; //archive.cpp line 136

        internal bool OldNumberingFormat { get; private set; }

        public bool IsRar5 { get; }

        private MarkHeader(bool isRar5)
        {
            IsRar5 = isRar5;
        }

        public HeaderType HeaderType => HeaderType.Mark;

        private static byte GetByte(Stream stream)
        {
            var b = stream.ReadByte();
            if (b != -1)
            {
                return (byte)b;
            }
            throw new EndOfStreamException();
        }

        public static MarkHeader Read(Stream stream, bool leaveStreamOpen, bool lookForHeader)
        {
            int maxScanIndex = lookForHeader ? MAX_SFX_SIZE : 0;
            try
            {
                int start = -1;
                var b = GetByte(stream); start++;
                while (start <= maxScanIndex)
                {
                    // Rar old signature: 52 45 7E 5E
                    // Rar4 signature:    52 61 72 21 1A 07 00
                    // Rar5 signature:    52 61 72 21 1A 07 01 00
                    if (b == 0x52)
                    {
                        b = GetByte(stream); start++;
                        if (b == 0x61)
                        {
                            b = GetByte(stream); start++;
                            if (b != 0x72)
                            {
                                continue;
                            }

                            b = GetByte(stream); start++;
                            if (b != 0x21)
                            {
                                continue;
                            }

                            b = GetByte(stream); start++;
                            if (b != 0x1a)
                            {
                                continue;
                            }

                            b = GetByte(stream); start++;
                            if (b != 0x07)
                            {
                                continue;
                            }

                            b = GetByte(stream); start++;
                            if (b == 1)
                            {
                                b = GetByte(stream); start++;
                                if (b != 0)
                                {
                                    continue;
                                }

                                return new MarkHeader(true); // Rar5
                            }
                            else if (b == 0)
                            {
                                return new MarkHeader(false); // Rar4
                            }
                        }
                        else if (b == 0x45)
                        {
                            b = GetByte(stream); start++;
                            if (b != 0x7e)
                            {
                                continue;
                            }

                            b = GetByte(stream); start++;
                            if (b != 0x5e)
                            {
                                continue;
                            }

                            throw new InvalidFormatException("Rar format version pre-4 is unsupported.");
                        }
                    }
                    else
                    {
                        b = GetByte(stream); start++;
                    }
                }
            }
            catch (Exception e)
            {
                if (!leaveStreamOpen)
                {
                    stream.Dispose();
                }
                throw new InvalidFormatException("Error trying to read rar signature.", e);
            }

            throw new InvalidFormatException("Rar signature not found");
        }
    }
}
